package com.lintf.starter.central.auth.redis;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.lintf.starter.central.auth.CustomToken;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.util.TimeZone;

/**
 * 自定义Token的Redis序列化器
 * 用于将CustomToken对象序列化和反序列化为Redis中的字节流
 */
public class CustomTokenRedisSerializer implements RedisSerializer<CustomToken> {

    private final ObjectMapper objectMapper;

    /**
     * 构造方法，初始化ObjectMapper
     */
    public CustomTokenRedisSerializer() {
        this.objectMapper = createObjectMapper();
        Jackson2JsonRedisSerializer<CustomToken> serializer =
                new Jackson2JsonRedisSerializer<>(objectMapper, CustomToken.class);
    }

    /**
     * 创建并配置ObjectMapper
     * 1. 配置日期/时间处理
     * 2. 配置多态类型支持
     * 3. 配置序列化/反序列化选项
     *
     * @return 配置好的ObjectMapper实例
     */
    private ObjectMapper createObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();

        // 设置默认时区为北京时间
        mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

        // 1. 配置日期/时间处理
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 2. 配置多态类型支持
        mapper.activateDefaultTyping(
                mapper.getPolymorphicTypeValidator(),
                ObjectMapper.DefaultTyping.EVERYTHING,
                JsonTypeInfo.As.PROPERTY
        );

        // 3. 配置序列化/反序列化选项
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        return mapper;
    }

    /**
     * 序列化CustomToken对象为字节流
     *
     * @param token 要序列化的CustomToken对象
     * @return 序列化后的字节流
     * @throws SerializationException 如果序列化失败
     */
    @Override
    public byte[] serialize(CustomToken token) throws SerializationException {
        if (token == null) {
            return new byte[0];
        }
        try {
            return objectMapper.writeValueAsBytes(token);
        } catch (Exception e) {
            throw new SerializationException("Could not serialize token", e);
        }
    }

    /**
     * 反序列化字节流为CustomToken对象
     *
     * @param bytes 要反序列化的字节流
     * @return 反序列化后的CustomToken对象
     * @throws SerializationException 如果反序列化失败
     */
    @Override
    public CustomToken deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            return objectMapper.readValue(bytes, CustomToken.class);
        } catch (Exception e) {
            throw new SerializationException("Could not deserialize token", e);
        }
    }
}
